package com.common.util;

import cn.hutool.core.convert.Convert;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.common.base.BaseConstant;
import com.entity.sys.SysRoleMenu;
import com.entity.sys.SysUser;
import com.service.sys.SysRoleMenuService;
import fuhua.com.util.EncryptionUtil;
import fuhua.com.util.RedisUtil;
import fuhua.com.vo.ExceptionVo;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 登录、token相关组件工具类
 */
public class LoginUtil {

    private static SysRoleMenuService sysRoleMenuService = SpringUtil.getBean(SysRoleMenuService.class);
    private static long tokeTime = 3600;

    /**
     * 登录
     * @param user 登录的用户信息
     */
    public static String login(SysUser user){
        return login(user,null,tokeTime);
    }

    /**
     * 登录（指定登录类型）
     * @param user 登录的用户信息
     * @param loginType 登录类型
     */
    public static String login(SysUser user,String loginType){
        return login(user,loginType,tokeTime);
    }

    /**
     * 登录（指定登录类型和有效时长）
     * @param user 登录的用户信息
     * @param loginType 登录类型
     * @param time token有效期
     */
    public static String login(SysUser user,String loginType,long time){
        String str = DigestUtil.md5Hex(String.valueOf(user.getId())); // userId加密
        //获取所有包含当前用户id加密后的字符串开头的key
        RedisUtil.del(RedisUtil.allKey(BaseConstant.cachePrefix + str + "*")); // 将旧的key删除
        if (loginType != null) str = loginType + "_" + str;
        String token = str + EncryptionUtil.generateRandom(32,false); // token组成为 用户id加密字符串+随机32为字符串
        Map<String,Object> map = new HashMap<>();
        map.put("token",token);
        map.put("createTime",System.currentTimeMillis());
        map.put("user",user);
        RedisUtil.hmset(BaseConstant.cachePrefix+token,map,time);
        return token;
    }

    /**
     * 退出（根据token退出）
     */
    public static void logout(String token){
        RedisUtil.del(BaseConstant.cachePrefix+token);
    }

    /**
     * 获取当前登录用户的token
     */
    public static String getToken(HttpServletRequest request){
        String token = request.getHeader(BaseConstant.tokenHeader);
        if (token == null || token.length() == 0 || !RedisUtil.hasKey(BaseConstant.cachePrefix+token)){
            throw new ExceptionVo(1003,"用户未登录");
        }
        return token;
    }

    /**
     * 获取当前用户的剩余有效时长
     */
    public static long getTimeOut(String token){
        return RedisUtil.getExpire(BaseConstant.cachePrefix+token);
    }

    /**
     * 获取当前登录信息
     */
    public static Map<String,Object> getLogin(String token){
        return RedisUtil.hmget(BaseConstant.cachePrefix+token);
    }

    /**
     * 获取当前用户
     */
    public static SysUser getLoginUser(String token){
        return (SysUser) RedisUtil.hget(BaseConstant.cachePrefix+token,"user");
    }

    /**
     * 获取当前用户token的创建时间
     */
    public static long getCreateTime(String token){
        return (Long) RedisUtil.hget(BaseConstant.cachePrefix+token,"createTime");
    }

    /**
     * 获取当前用户的所有权限集合
     */
    public static List<String> getPermList(String token,List<String> roleList){
        if (roleList == null){
            roleList = getRoleList(token);
        }
        List<String> permList = new ArrayList<>();
        if (RedisUtil.hasKey(BaseConstant.rolePermList)) { // 如果redis中有所有角色对应的所有权限，直接从redis中拿
            Map<String, Object> map = RedisUtil.hmget(BaseConstant.rolePermList);
            for (String role : roleList) {
                String[] split = role.split(",");
                for (int i = 0; i < split.length; i++) {
                    permList.addAll((List<String>) map.get(split[i]));
                }
            }
        }else {
            // redis没有，则去数据库查询，并将查询到的数据设置到redis中
            List<SysRoleMenu> allRolePerm = sysRoleMenuService.listAll();
            Map<String, List<SysRoleMenu>> group = allRolePerm.stream().collect(Collectors.groupingBy(SysRoleMenu::getRoleId));
            Map<String, List<String>> map = new HashMap<>();
            for (String key : group.keySet()) {
                List<String> perms = group.get(key).stream().map(SysRoleMenu::getMenuId).collect(Collectors.toList());
                map.put(key,perms);
                if (roleList.contains(key)){
                    permList.addAll(perms);
                }
            }
            RedisUtil.hmset(BaseConstant.rolePermList,map);
        }
        return permList;
    }

    /**
     * 获取当前用户的所有角色集合
     */
    public static List<String> getRoleList(String token){
        return Convert.toList(String.class,getLoginUser(token).getRoleId());
    }

    /**
     * 刷新过期时间
     */
    public static void updateTimeOut(String token){
        updateTimeOut(token,tokeTime);
    }

    /**
     * 刷新过期时间（指定过期时间）
     */
    public static void updateTimeOut(String token,long time){
        RedisUtil.hmset(BaseConstant.cachePrefix+token,getLogin(token),time);
    }

    /**
     * 更新用户信息
     */
    public static void updateUser(String token,SysUser user){
        RedisUtil.hset(BaseConstant.cachePrefix+token,"user",user);
    }

}
